﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Collections.Specialized;
using System.Configuration;
using System.Xml;
using System.Reflection;

namespace PDDP
{
    public partial class frmPackage : Form
    {
        #region Private variáveis

        private string[] aprocs;
        private string[] afuncs;
        private string duplicado = "";
        List<string> refer = new List<string>();
        List<string> avisos = new List<string>();
        private int ind = 0;

        #endregion

        #region Eventos de tela

        public frmPackage()
        {
            InitializeComponent();
            NameValueCollection appSettings = ConfigurationManager.AppSettings;
            txtPasta.Text = appSettings["caminho"];
        }

        private void btoProcessar_Click(object sender, EventArgs e)
        {
            TextReader textReader;
            int nnodeproc = 0;
            int nnodefunc = 0;
            int nlin = 0;
            string objeto;
            string linha;
            string nomearq;
            string package = "";
            StringBuilder funcs = new StringBuilder();
            StringBuilder procs = new StringBuilder();
            TreeNode tree;
            bool bbody;
            string[] files = Directory.GetFiles(txtPasta.Text);
            lstLog.Items.Clear();
            trvObject.Nodes.Clear();
            txtArquivo.Text = "";
            txtRotulo.Text = "";
            txtPackage.Text = "";

            for (int i = 0; i < files.Length; i++)
            {
                textReader = new StreamReader(files[i]);
                linha = textReader.ReadLine();
                nomearq = files[i].Replace(txtPasta.Text, "").ToUpper();
                nlin = 0;
                bbody = false;

				while (linha != null) 
				{
                    nlin++;

                    if (!bbody)
                    {

                        if (linha.ToLower().IndexOf("create") >= 0 &&
                            linha.ToLower().IndexOf("package") >= 0 &&
                            (linha.IndexOf("--") < 0 || linha.IndexOf("--") > linha.ToLower().IndexOf("package")) &&
                            (linha.IndexOf("/*") < 0 || linha.IndexOf("/*") > linha.ToLower().IndexOf("package")) &&
                            linha.IndexOf("start") < 0)
                        {
                            package = ObterObjeto("package", linha);

                            if (package.Length > 0)
                            {
                                lstLog.Items.Add(string.Format("{0} - linha {1} - {2}", package, nlin, files[i]));
                                tree = new TreeNode(package);
                                tree.Name = package;
                                tree.ToolTipText = files[i];
                                trvObject.Nodes.Add(tree);
                            }

                        }
                        else
                        {

                            if (linha.ToLower().IndexOf("procedure") >= 0 &&
                                (linha.IndexOf("--") < 0 || linha.IndexOf("--") > linha.ToLower().IndexOf("procedure")) &&
                                (linha.IndexOf("/*") < 0 || linha.IndexOf("/*") > linha.ToLower().IndexOf("procedure")) &&
                                linha.IndexOf("start") < 0)
                            {
                                objeto = ObterObjeto("procedure", linha);

                                if (objeto.Length > 0)
                                {
                                    lstLog.Items.Add(string.Format("{0} - linha {1} - {2}", objeto, nlin, files[i]));

                                    if (trvObject.Nodes[trvObject.Nodes.Count - 1].Nodes.Find("procedure", false).Length == 0)
                                    {
                                        tree = new TreeNode("procedure");
                                        tree.Name = "procedure";
                                        trvObject.Nodes[trvObject.Nodes.Count - 1].Nodes.Add(tree);
                                        nnodeproc = trvObject.Nodes[trvObject.Nodes.Count - 1].Nodes.Count - 1;
                                    }

                                    procs.Append(package);
                                    procs.Append(".");
                                    procs.Append(objeto);
                                    procs.Append("|");
                                    tree = new TreeNode(objeto);
                                    tree.Name = objeto;
                                    tree.ToolTipText = files[i];
                                    trvObject.Nodes[trvObject.Nodes.Count - 1].Nodes[nnodeproc].Nodes.Add(tree);
                                }

                            }
                            else
                            {

                                if (linha.ToLower().IndexOf("function") >= 0 &&
                                    (linha.IndexOf("--") < 0 || linha.IndexOf("--") > linha.ToLower().IndexOf("function")) &&
                                    (linha.IndexOf("/*") < 0 || linha.IndexOf("/*") > linha.ToLower().IndexOf("function")) &&
                                    linha.IndexOf("start") < 0)
                                {
                                    objeto = ObterObjeto("function", linha);

                                    if (objeto.Length > 0)
                                    {
                                        lstLog.Items.Add(string.Format("{0} - linha {1} - {2}", objeto, nlin, files[i]));

                                        if (trvObject.Nodes[trvObject.Nodes.Count - 1].Nodes.Find("function", false).Length == 0)
                                        {
                                            tree = new TreeNode("function");
                                            tree.Name = "function";
                                            trvObject.Nodes[trvObject.Nodes.Count - 1].Nodes.Add(tree);
                                            nnodefunc = trvObject.Nodes[trvObject.Nodes.Count - 1].Nodes.Count - 1;
                                        }

                                        funcs.Append(package);
                                        funcs.Append(".");
                                        funcs.Append(objeto);
                                        funcs.Append("|");
                                        tree = new TreeNode(objeto);
                                        tree.Name = objeto;
                                        tree.ToolTipText = files[i];
                                        trvObject.Nodes[trvObject.Nodes.Count - 1].Nodes[nnodefunc].Nodes.Add(tree);
                                    }

                                }

                            }

                        }

                    }
                    else
                    {
                        if (linha.ToLower().IndexOf("procedure") >= 0 &&
                            (linha.IndexOf("--") < 0 || linha.IndexOf("--") > linha.ToLower().IndexOf("procedure")) &&
                            (linha.IndexOf("/*") < 0 || linha.IndexOf("/*") > linha.ToLower().IndexOf("procedure")))
                        {
                            objeto = ObterObjeto("procedure", linha);

                            if (objeto.Length > 0 && procs.ToString().IndexOf(objeto + "|") < 0)
                            {
                                lstLog.Items.Add(string.Format("{0} - linha {1} - {2}", objeto, nlin, files[i]));

                                if (trvObject.Nodes[trvObject.Nodes.Count - 1].Nodes.Find("proc local", false).Length == 0)
                                {
                                    tree = new TreeNode("proc local");
                                    tree.Name = "proc local";
                                    trvObject.Nodes[trvObject.Nodes.Count - 1].Nodes.Add(tree);
                                    nnodeproc = trvObject.Nodes[trvObject.Nodes.Count - 1].Nodes.Count - 1;
                                }

                                tree = new TreeNode(objeto);
                                tree.Name = objeto;
                                trvObject.Nodes[trvObject.Nodes.Count - 1].Nodes[nnodeproc].Nodes.Add(tree);
                            }

                        }
                        else
                        {

                            if (linha.ToLower().IndexOf("function") >= 0 &&
                                (linha.IndexOf("--") < 0 || linha.IndexOf("--") > linha.ToLower().IndexOf("function")) &&
                                (linha.IndexOf("/*") < 0 || linha.IndexOf("/*") > linha.ToLower().IndexOf("function")))
                            {
                                objeto = ObterObjeto("function", linha);

                                if (objeto.Length > 0 && funcs.ToString().IndexOf(objeto + "|") < 0)
                                {
                                    lstLog.Items.Add(string.Format("{0} - linha {1} - {2}", objeto, nlin, files[i]));

                                    if (trvObject.Nodes[trvObject.Nodes.Count - 1].Nodes.Find("func local", false).Length == 0)
                                    {
                                        tree = new TreeNode("func local");
                                        tree.Name = "func local";
                                        trvObject.Nodes[trvObject.Nodes.Count - 1].Nodes.Add(tree);
                                        nnodefunc = trvObject.Nodes[trvObject.Nodes.Count - 1].Nodes.Count - 1;
                                    }

                                    tree = new TreeNode(objeto);
                                    tree.Name = objeto;
                                    trvObject.Nodes[trvObject.Nodes.Count - 1].Nodes[nnodefunc].Nodes.Add(tree);
                                }

                            }

                        }

                    }

                    linha = textReader.ReadLine();

                    if (linha != null &&
                        !bbody &&
                        (linha.ToLower().IndexOf("create") >= 0 && 
                        linha.ToLower().IndexOf("package") >= 0 && 
                        linha.ToLower().IndexOf("body") >= 0 &&
                        (linha.IndexOf("--") < 0 || linha.IndexOf("--") > linha.ToLower().IndexOf("body")) &&
                        (linha.IndexOf("/*") < 0 || linha.IndexOf("/*") > linha.ToLower().IndexOf("body"))))
                    {
                        bbody = true;
                    }

                }

            }

            char[] sep = { '|' };
            aprocs = procs.ToString().Split(sep, StringSplitOptions.RemoveEmptyEntries);
            afuncs = funcs.ToString().Split(sep, StringSplitOptions.RemoveEmptyEntries);

            for (int i = 0; i < files.Length; i++)
            {
                Dependencias(files[i]);
            }

            AtualizaDependencia();
        }

        private void frmPakage_KeyDown(object sender, KeyEventArgs e)
        {

            if (e.Control && (e.KeyValue == 70 || e.KeyValue == 102))
            {
                frmPesquisa form = new frmPesquisa();

                if (txtRotulo.Focused)
                    form.Tag = txtRotulo.SelectedText;
                else if (txtArquivo.Focused)
                    form.Tag = txtArquivo.SelectedText;
                else if (txtPackage.Focused)
                    form.Tag = txtPackage.SelectedText;

                form.ShowDialog();

                if (form.DialogResult == DialogResult.OK && !form.Tag.ToString().Equals(""))
                {
                    TreeNode[] treefind = trvObject.Nodes.Find(form.Tag.ToString().ToLower(), false);

                    if (treefind.Length > 0)
                    {
                        trvObject.Focus();
                        trvObject.SelectedNode = treefind[0];
                    }
                    else
                    {
                        MessageBox.Show("A package " + form.Tag.ToString().ToLower() + " não foi encontrada!", "Aviso!", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }

                }

            }

            if (!e.Control && !e.Shift && e.KeyValue == 13)
            {
                btoProcessar_Click(null, null);
            }
        }

        private void btoAviso_Click(object sender, EventArgs e)
        {
            if (avisos.Count <= 0)
            {
                MessageBox.Show("Não foram gerados avisos durante este processamento!", "Aviso!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            else
            {
                frmAviso form = new frmAviso();
                form.Tag = avisos;
                form.ShowDialog();
            }
                                        

        }

        private void trvObject_AfterSelect(object sender, TreeViewEventArgs e)
        {

            TreeNode treeSelected = ((TreeView)sender).SelectedNode;

            if (treeSelected != null)
            {

                if (treeSelected.ToolTipText != "")
                {
                    TextReader textReader = new StreamReader(treeSelected.ToolTipText, Encoding.Default);
                    txtArquivo.Text = treeSelected.ToolTipText;
                    txtPackage.Text = textReader.ReadToEnd();
                    textReader.Close();
                }

                txtRotulo.Text = treeSelected.Name;
            }

        }

        private void btoConfig_Click(object sender, EventArgs e)
        {
            fbdPasta.SelectedPath = txtPasta.Text;
            fbdPasta.ShowDialog();
            txtPasta.Text = fbdPasta.SelectedPath;
            NameValueCollection appSettings = ConfigurationManager.AppSettings;
            appSettings["caminho"] = txtPasta.Text;

            XmlDocument doc = null;

            try
            {
                doc = new XmlDocument();
                doc.Load(Assembly.GetExecutingAssembly().Location + ".config");
                XmlNodeList nodelist = doc.SelectNodes("//configuration//appSettings//add");

                foreach (XmlNode node in nodelist)
                {

                    if (node.Attributes["key"] != null && node.Attributes["key"].Value == "caminho")
                    {

                        if (node.Attributes["value"] != null)
                        {
                            node.Attributes["value"].Value = txtPasta.Text;
                        }

                    }

                }

                doc.Save(Assembly.GetExecutingAssembly().Location + ".config");
            }
            catch
            {
                MessageBox.Show("Ocorreu algum problema na gravação do arquivo de configuração!", "Erro!", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }

        private string ObterObjeto(string objeto, string linha)
        {
            string retorno = "";
            char[] sep = { ' ', '(', '\t', ';' };
            string[] linhasplit = linha.Split(sep, StringSplitOptions.RemoveEmptyEntries);

            for (int i = 0; i < linhasplit.Length; i++)
            {

                if (linhasplit[i].ToLower() == objeto.ToLower())
                    if (i < linhasplit.Length - 1)
                    {
                        retorno = linhasplit[i + 1].ToLower();
                        break;
                    }

            }

            return retorno;
        }

        #endregion

        #region Rotinas locais

        private void Dependencias(string arquivo)
        {
            NameValueCollection appSettings = ConfigurationManager.AppSettings;
            TextReader textReader;
            string linha;
            string nomearq;
            TreeNode tree;
            TreeNode[] findpack = null;
            bool bbody = false;
            int j = 0;

            textReader = new StreamReader(arquivo);
            linha = textReader.ReadLine();
            nomearq = arquivo.Replace(appSettings["caminho"], "").ToUpper();

            while (linha != null)
            {

                if (!bbody)
                {

                    if (linha.ToLower().IndexOf("create") >= 0 &&
                        linha.ToLower().IndexOf("package") >= 0 &&
                        linha.ToLower().IndexOf("body") < 0 &&
                        (linha.IndexOf("--") < 0 || linha.IndexOf("--") > linha.ToLower().IndexOf("package")) &&
                        (linha.IndexOf("/*") < 0 || linha.IndexOf("/*") > linha.ToLower().IndexOf("package")) &&
                        linha.IndexOf("start") < 0)
                    {
                        findpack = trvObject.Nodes.Find(ObterObjeto("package", linha), false);

                        if (findpack[0].Name != duplicado && findpack.Length > 1)
                        {
                            duplicado = findpack[0].Name;
                            avisos.Add("A package " + duplicado + " existe em mais de um arquivo!");
                        }

                        if (findpack.Length > 1)
                        {
                            for (int i = 0; i < findpack.Length; i++)
                                findpack[i].ForeColor = Color.Chocolate;
                        }

                        for (int i = 0; i < findpack.Length; i++)
                        {

                            if (findpack[i].ToolTipText == arquivo)
                            {
                                j = i;
                                break;
                            }

                        }

                    }

                }
                else
                {

                    for (int i = 0; i < aprocs.Length; i++)
                    {

                        if (linha.ToLower().IndexOf(aprocs[i]) >= 0 && linha.ToLower().IndexOf(findpack[j].Text) < 0)
                        {

                            if (findpack[j].Nodes.Find("dependencias", true).Length == 0)
                            {
                                tree = new TreeNode("dependencias");
                                tree.Name = "dependencias";
                                findpack[j].Nodes.Add(tree);
                            }

                            if (findpack[j].Nodes.Find(aprocs[i], true).Length == 0)
                            {
                                tree = new TreeNode(aprocs[i]);
                                tree.Name = aprocs[i];
                                findpack[j].Nodes[findpack[j].Nodes.Count - 1].Nodes.Add(tree);
                            }

                        }

                    }

                    for (int i = 0; i < afuncs.Length; i++)
                    {

                        if (linha.ToLower().IndexOf(afuncs[i]) >= 0)
                        {

                            if (linha.ToLower().IndexOf(afuncs[i]) >= 0 && (linha.ToLower().IndexOf(afuncs[i]) < linha.ToLower().IndexOf("'") || linha.ToLower().IndexOf("'") < 0))
                            {

                                if (findpack[j].Nodes.Find("dependencias", true).Length == 0)
                                {
                                    tree = new TreeNode("dependencias");
                                    tree.Name = "dependencias";
                                    findpack[j].Nodes.Add(tree);
                                }

                                if (findpack[j].Nodes.Find(afuncs[i], true).Length == 0)
                                {
                                    tree = new TreeNode(afuncs[i]);
                                    tree.Name = afuncs[i];
                                    findpack[j].Nodes[findpack[j].Nodes.Count - 1].Nodes.Add(tree);
                                }

                            }

                        }

                    }

                }

                if (!bbody && 
                    linha.ToLower().IndexOf("create") >= 0 &&
                    linha.ToLower().IndexOf("package") >= 0 &&
                    linha.ToLower().IndexOf("body") >= 0 &&
                    (linha.IndexOf("--") < 0 || linha.IndexOf("--") > linha.ToLower().IndexOf("body")) &&
                    (linha.IndexOf("/*") < 0 || linha.IndexOf("/*") > linha.ToLower().IndexOf("body")))
                {
                    bbody = true;
                }

                linha = textReader.ReadLine();
            }

        }

        private void AtualizaDependencia()
        {
            TreeNode[] findpack;
            TreeNode tree;

            for (int i = 0; i < trvObject.Nodes.Count; i++)
            {
                tree = trvObject.Nodes[i];
                findpack = tree.Nodes.Find("dependencias", true);

                if (findpack.Length > 0)
                {
                    ObterDependencias(i);
                }

            }

        }

        private TreeNode ObterDependencias(int item)
        {
            TreeNode findpack;
            TreeNode[] finddep;
            TreeNode[] findall;
            TreeNode tree = null;
            TreeNode treeret = new TreeNode();
            bool recursividade;
            string findText;
            findpack = trvObject.Nodes[item];
            finddep = findpack.Nodes.Find("dependencias", false);
            ind++;

            if (finddep.Length > 0)
            {

                for (int j = 0; j < finddep[0].Nodes.Count; j++)
                {
                    findText = finddep[0].Nodes[j].Text.Substring(0, finddep[0].Nodes[j].Text.IndexOf("."));
                    findall = trvObject.Nodes.Find(findText, false);
                    recursividade = false;

                    if (refer.IndexOf(findText) < 0)
                    {
                        refer.Add(findText);
                        tree = ObterDependencias(findall[0].Index);
                    }
                    else
                    {
                        recursividade = true;
                    }

                    if (tree != null)
                    {

                        if (ind != 1)
                        {

                            if (recursividade)
                            {
                                tree = new TreeNode();
                                tree.ForeColor = Color.DodgerBlue;
                            }

                            tree.Name = findall[0].Name;
                            tree.Text = findall[0].Text;

                            if (treeret.Nodes.Find(tree.Name, false).Length == 0)
                            {

                                if (recursividade && avisos.IndexOf("O objeto " + tree.Name + " apresenta recursividade!") < 0)
                                {
                                    avisos.Add("O objeto " + tree.Name + " apresenta recursividade!");
                                }

                                treeret.Nodes.Add(tree);
                            }

                        }
                        else
                        {

                            for (int i = 0; i < tree.Nodes.Count; i++)
                            {
                                finddep[0].Nodes[j].Nodes.Add(tree.Nodes[i]);
                            }

                        }

                    }
                    else
                    {
                        tree = new TreeNode(finddep[0].Nodes[j].Text);
                        tree.Name = finddep[0].Nodes[j].Text;

                        if (recursividade)
                        {
                            tree.ForeColor = Color.DodgerBlue;
                        }

                        if (treeret.Nodes.Find(tree.Name, false).Length == 0)
                        {

                            if (recursividade && avisos.IndexOf("O objeto " + tree.Name + " apresenta recursividade!") < 0)
                            {
                                avisos.Add("O objeto " + tree.Name + " apresenta recursividade!");
                            }

                            treeret.Nodes.Add(tree);
                        }

                    }

                }

            }
            else
            {
                treeret = null;
            }

            ind--;
            if (refer.Count > 0)
                refer.RemoveAt(refer.Count - 1);
            return treeret;
        }

        #endregion

   }

}
